﻿// DX12.cpp : 定义应用程序的入口点。
//

#include "DX12.h"

// 全局变量:
ikit::XmlReader config(CONFIG_FILE);
WindowApp app;
ifire::DxWindow dx_app;
ifire::TestConsole* tconsole = nullptr; // 测试控制台
ifire::UnitTest* unit_test = nullptr;
std::unique_ptr<ifire::DxScene> room_scene;
std::unique_ptr<ifire::DxScene> mountain_water_scene;
std::unique_ptr<ifire::DxScene> vec_add_scene;
std::unique_ptr<ifire::DxScene> tess_basic;
std::unique_ptr<ifire::DxScene> tess_patch;
std::unique_ptr<ifire::DxScene> altar_scene;
std::unique_ptr<ifire::DxScene> instanced_scene;
std::unique_ptr<ifire::DxScene> pick_scene;
std::unique_ptr<ifire::DxScene> cube_scene;
std::unique_ptr<ifire::DxScene> dynamic_cube_scene;
std::unique_ptr<ifire::DxScene> normal_scene;
std::unique_ptr<ifire::DxScene> shadows_scene;
std::unique_ptr<ifire::DxScene> ssao_scene;
std::unique_ptr<ifire::DxScene> skin_scene;

void RegisterAction();

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine,
    _In_ int nCmdShow) {
// 针对调试版本开启运行时内存检查
#if defined(DEBUG) | defined(_DEBUG)
  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

  // 设置输出LOG文件
  ikit::set_log_output_file(LOG_FILE, false);

  RegisterAction();

  // 创建Window
  app.Init(hInstance, lpCmdLine, nCmdShow);
  app.CreateWinForm(config["AppName"].GbkValue().c_str(), config["Width"].Int(),
      config["Height"].Int());

  ifire::g_timer.Reset();

  // 如果是DEBUG模式，则创建Console
  if (DEBUG_MODE) {
    tconsole = new ifire::TestConsole(&app, app.GetHeight() - 205);
    tconsole->Init();
    unit_test = new ifire::DirectXTest();
    tconsole->SignTest("DirectX Test", unit_test);
    app.RegisterCommandHandle([](int id) { tconsole->OnCommand(id); });
  }

  // 主循环
  while (!app.IsExited()) {
    app.RollEvents();
    if (dx_app.Run()) {
      app.SetTitle(ifire::g_timer.GetFpsFormat("Fps: %.0f"));
    }
  }

  // 退出
  return (int)app.GetMsgWParam();
}

void OpenScene(ifire::DxScene* scene) {
  dx_app.Close();
  // 通当前的位置计算，将其放在一边
  auto rect = app.GetRect();
  RECT client_rect = {                               //
      static_cast<LONG>(rect.left + app.GetWidth()), //
      rect.top,                                      //
      config["Width"].Int(),                         //
      config["Height"].Int()};
  dx_app.SetScene(scene);
  dx_app.OpenWindow(app.GetHandle(), client_rect);
  KLOG("OpenDirectX!");
}

void CheckShader() {
  using ifire::dxutils::compile_shader;

  const D3D_SHADER_MACRO waveDefines[] = {"DISPLACEMENT_MAP", "1", NULL, NULL};
  try {
    ComPtr<ID3DBlob> vertex_shader =
        compile_shader("shaders/Default.hlsl", nullptr, "VS", "vs_5_0");
    ComPtr<ID3DBlob> pixel_shader =
        compile_shader("shaders/Default.hlsl", nullptr, "PS", "ps_5_0");
    ComPtr<ID3DBlob> wave_shader =
        compile_shader("shaders/Default.hlsl", waveDefines, "VS", "vs_5_0");
    tconsole->PrintLine("Default.hlsl 成功编译完成.");
  } catch (ifire::DxException e) {
    tconsole->PrintLine(e.ToString().c_str());
  }

  try {
    ComPtr<ID3DBlob> vs_shader =
        compile_shader("shaders/TreeSprite.hlsl", nullptr, "VS", "vs_5_0");
    ComPtr<ID3DBlob> gs_shader =
        compile_shader("shaders/TreeSprite.hlsl", nullptr, "GS", "gs_5_0");
    ComPtr<ID3DBlob> ps_shader =
        compile_shader("shaders/TreeSprite.hlsl", nullptr, "PS", "ps_5_0");
    tconsole->PrintLine("TreeSprite.hlsl 成功编译完成.");
  } catch (ifire::DxException e) {
    tconsole->PrintLine(e.ToString().c_str());
  }

  try {
    ComPtr<ID3DBlob> vs_shader =
        compile_shader("shaders/VecAdd.hlsl", nullptr, "CS", "cs_5_0");
    tconsole->PrintLine("VecAdd.hlsl 成功编译完成.");
  } catch (ifire::DxException e) {
    tconsole->PrintLine(e.ToString().c_str());
  }

  try {
    ComPtr<ID3DBlob> blurh_shader =
        compile_shader("shaders/Blur.hlsl", nullptr, "HorzBlurCS", "cs_5_0");
    ComPtr<ID3DBlob> blurv_shader =
        compile_shader("shaders/Blur.hlsl", nullptr, "VertBlurCS", "cs_5_0");
    tconsole->PrintLine("Blur.hlsl 成功编译完成.");
  } catch (ifire::DxException e) {
    tconsole->PrintLine(e.ToString().c_str());
  }

  try {
    ComPtr<ID3DBlob> blurh_shader = compile_shader(
        "shaders/WaveSim.hlsl", nullptr, "UpdateWavesCS", "cs_5_0");
    ComPtr<ID3DBlob> blurv_shader = compile_shader(
        "shaders/WaveSim.hlsl", nullptr, "DisturbWavesCS", "cs_5_0");
    tconsole->PrintLine("WaveSim.hlsl 成功编译完成.");
  } catch (ifire::DxException e) {
    tconsole->PrintLine(e.ToString().c_str());
  }
}

void RegisterAction() {
  using ifire::DxScene;
  using ifire::DxSceneID;
  // 创建Scene
  room_scene = std::make_unique<DxScene>(DxSceneID::ROOM);
  mountain_water_scene = std::make_unique<DxScene>(DxSceneID::WATER);
  vec_add_scene = std::make_unique<DxScene>(DxSceneID::VEC_ADD);
  tess_basic = std::make_unique<DxScene>(DxSceneID::TESS_BASIC);
  tess_patch = std::make_unique<DxScene>(DxSceneID::TESS_PATCH);
  altar_scene = std::make_unique<DxScene>(DxSceneID::ALTAR);
  instanced_scene = std::make_unique<DxScene>(DxSceneID::INSTANED);
  pick_scene = std::make_unique<DxScene>(DxSceneID::PICK);
  cube_scene = std::make_unique<DxScene>(DxSceneID::CUBE);
  dynamic_cube_scene = std::make_unique<DxScene>(DxSceneID::DYNAMIC_CUBE);
  normal_scene = std::make_unique<DxScene>(DxSceneID::NORMAL);
  shadows_scene = std::make_unique<DxScene>(DxSceneID::SHADOWS);
  ssao_scene = std::make_unique<DxScene>(DxSceneID::SSAO);
  skin_scene = std::make_unique<DxScene>(DxSceneID::SKIN);

  // 设置DX的输出流
  auto output = [](std::string msg) { tconsole->PrintLine(msg.c_str()); };
  ifire::dxutils::set_output_stream(output);

  app.RegisterAction("曲面细分", []() { OpenScene(tess_basic.get()); });
  app.RegisterAction("贝赛尔平面", []() { OpenScene(tess_patch.get()); });
  app.RegisterAction("镜子房间", []() { OpenScene(room_scene.get()); });
  app.RegisterAction("山水", []() { OpenScene(mountain_water_scene.get()); });
  app.RegisterAction("祭坛", []() { OpenScene(altar_scene.get()); });
  app.RegisterAction("向量累加", []() { OpenScene(vec_add_scene.get()); });
  app.RegisterAction("实例/剔除", []() { OpenScene(instanced_scene.get()); });
  app.RegisterAction("射线捡取", []() { OpenScene(pick_scene.get()); });
  app.RegisterAction("天空盒", []() { OpenScene(cube_scene.get()); });
  app.RegisterAction("动态天空盒", []() { OpenScene(dynamic_cube_scene.get()); });
  app.RegisterAction("编译Shader", CheckShader);
  app.RegisterAction("法线贴图", []() { OpenScene(normal_scene.get()); });
  app.RegisterAction("阴影贴图", []() { OpenScene(shadows_scene.get()); });
  app.RegisterAction("环境光遮蔽", []() { OpenScene(ssao_scene.get()); });
  app.RegisterAction("蒙皮骨骼", []() { OpenScene(skin_scene.get()); });
}